package com.rpoonolly.simpleandroidgame;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;

import com.rpoonolly.simplegame.Config;
import com.rpoonolly.simplegame.core.aabb.AABBEntity;

public class RenderLoop implements SurfaceHolder.Callback, Runnable {
	private SurfaceHolder worldViewHolder;
	private Map<String, List<AABBEntity>> gameWorld;
	private List<AndroidRenderer> renderers;
	private Thread threadHndl = null;
	private AABBEntity focus;

	private MutableLock<Boolean> frame_rendered_flag;
	private boolean isSurfaceAvailable = false;
	private volatile boolean stop_flag = false;
	private volatile int windowWidth, windowHeight;
	
	public RenderLoop(Map<String, List<AABBEntity>> world, Context context, MutableLock<Boolean> frame_rendered_flag) {
		this.frame_rendered_flag = frame_rendered_flag;

		gameWorld = world;
		
		Paint paint;
		focus = gameWorld.get(Config.ENT_GRP_PLAYER).get(0);
		Map<String, Paint> entityToPaintMap = new ConcurrentHashMap<String, Paint>(3);
		
		paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setColor(Color.GREEN);
		entityToPaintMap.put(Config.ENT_GRP_WORLD_OBJS, paint);
		
		paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setColor(Color.RED);
		entityToPaintMap.put(Config.ENT_GRP_ENEMIES, paint);
		
		paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setColor(Color.BLUE);
		entityToPaintMap.put(Config.ENT_GRP_PLAYER, paint);
		
		AndroidRenderer mainRenderer = new AndroidRenderer();
		mainRenderer.setEntityGroupToPaintMap(entityToPaintMap);
		
		renderers = new CopyOnWriteArrayList<AndroidRenderer>();
		renderers.add(mainRenderer);
	}
	
	@Override
	public void run() {
		Canvas canvas = null;
		
		while (!stop_flag) {
			synchronized(frame_rendered_flag) {
				while(frame_rendered_flag.getValue()) {
					try {
						frame_rendered_flag.wait();
					} catch (InterruptedException e) {}
					if (stop_flag) return;
				}
			}
			
			do {
				synchronized (this) {
					while(!isSurfaceAvailable) {
						try {
							wait();
						} catch (InterruptedException e) {}
						if (stop_flag) return;
					}
				}
				
				canvas = worldViewHolder.lockCanvas();
			} while (canvas == null);
			
			canvas.drawColor(Color.BLACK);
			for(AndroidRenderer renderer : renderers) {
				renderer.setFocalPoint(focus);
				renderer.setCanvas(canvas);
				renderer.setWindowWidth(windowWidth);
				renderer.setWindowHeight(windowHeight);
				renderer.render(gameWorld);
			}
			
			worldViewHolder.unlockCanvasAndPost(canvas);
			
			synchronized(frame_rendered_flag) {
				frame_rendered_flag.setValue(true);
				frame_rendered_flag.notify();
			}
		}
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		windowWidth = width;
		windowHeight = height;
		System.out.println("SURFACE: changed");
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		synchronized(this) {
			worldViewHolder = holder;
			isSurfaceAvailable = true;
			notifyAll();
		}
		
		System.out.println("SURFACE: created");
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		synchronized(this) {
			isSurfaceAvailable = false;
		}
		System.out.println("SURFACE: destroyed");
	}
	
	public void start() {
		if(threadHndl == null) threadHndl = new Thread(this);
		threadHndl.start();
		stop_flag = false;
	}
	
	public void stop() {
		stop_flag = true;
		
		try {
			threadHndl.interrupt();
			threadHndl.join();
		} catch (InterruptedException e) {}
	}
}
